/*
 * Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.websocket.sample;

import com.google.websocket.AdamBarthHandshake;
import com.google.websocket.ExtensionData;
import com.google.websocket.WebSocket;
import com.google.websocket.WebSocket.Callback;
import com.google.websocket.WebSocketConnector;
import com.google.websocket.WebSocketHandshake;
import com.google.websocket.WebSocketListener;
import com.google.websocket.WebSocketListener.ListenCallback;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Set;

/**
 * Sample WebSocket command-line app.
 */
public class WebSocketTalk {

  /**
   * @param args
   * @throws IOException 
   * @throws URISyntaxException 
   */
  public static void main(String[] args) throws IOException, URISyntaxException {
    boolean server = false;
    String proxy = null;
    int argIndex = 0;
    if (args.length > argIndex + 1 && "-proxy".equals(args[argIndex])) {
      argIndex++;
      proxy = args[argIndex++];
    }
    if (args.length > argIndex && "-server".equals(args[argIndex])) {
      server = true;
      argIndex++;
    }
    if (argIndex >= args.length) {
      System.err.println("Usage: WebSocketTalk [-proxy host:port] [-server] "
          + "[host:]port");
      System.exit(1);
    }
    String hostPort = args[argIndex];
    String host = "localhost";
    int colon = hostPort.indexOf(':');
    if (colon >= 0) {
      host = hostPort.substring(0, colon);
      hostPort = hostPort.substring(colon + 1);
    }
    int port = Integer.parseInt(hostPort);
    WebSocketHandshake handshake = new AdamBarthHandshake();
    if (server) {
      WebSocketListener.listen(handshake, port, new ListenCallback() {
        public void onConnection(final WebSocket socket,
            SocketAddress remoteSocketAddress) {
          System.out.println("Connection received from " + remoteSocketAddress);
          Thread thread = new Thread() {
            @Override
            public void run() {
              final boolean[] stillOpen = new boolean[] { true };
              while (stillOpen[0]) {
                try {
                  socket.readOneMessage(new Callback() {
                    public void onBinaryMessage(
                        byte[] message, Set<ExtensionData> metadata)
                        throws IOException {
                      System.err.println("server received " + message.length
                          + " bytes in a binary message");
                    }

                    public void onClose() {
                      stillOpen[0] = false;
                    }

                    public void onFramingError() {
                      System.err.println("server received framing error");
                    }

                    public void onTextMessage(String text,
                        Set<ExtensionData> metadata) {
                      System.err.println("server received: " + text);
                    }
                  });
                } catch (IOException e) {
                  e.printStackTrace();
                  stillOpen[0] = false;
                }
              }
              try {
                socket.close();
              } catch (IOException e) {
                // ignore errors here, such as already closed
              }
            }
          };
          thread.setName("Connection from " + remoteSocketAddress);
          thread.start();
        }

        public void onException(SocketAddress remoteAddress, IOException e) {
          System.err.println("server got exception via " + remoteAddress);
          e.printStackTrace(System.err);
        }
      });
    } else {
      WebSocketConnector connector;
      if (proxy != null) {
        colon = proxy.indexOf(':');
        String proxyHost;
        int proxyPort;
        if (colon >= 0) {
          proxyHost = proxy.substring(0, colon);
          proxyPort = Integer.parseInt(proxy.substring(colon + 1));
        } else {
          proxyHost = proxy;
          proxyPort = 3128; // TODO(jat): should we default the port?
        }
        connector = new WebSocketConnector(handshake, proxyHost, proxyPort);
      } else {
        connector = new WebSocketConnector(handshake);
      }
      URI uri = new URI("ws://" + host + ":" + port + "/");
      WebSocket socket = connector.connect(uri, host + ":" + port);
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
      String line;      
      while ((line = reader.readLine()) != null) {
        socket.sendTextMessage(Collections.<ExtensionData>emptySet(), line);
      }
      socket.close();
    }
  }
}
